package VNFmeetsVON_MRDP_5modes;

import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;

import test.Posong;
import cern.colt.matrix.tdouble.DoubleFactory1D;
import cern.colt.matrix.tdouble.DoubleFactory2D;
import cern.colt.matrix.tdouble.DoubleMatrix1D;
import cern.colt.matrix.tdouble.DoubleMatrix2D;
import cern.colt.matrix.tint.IntFactory1D;
import cern.jet.math.tdouble.DoubleFunctions;


import com.net2plan.interfaces.networkDesign.Demand;
import com.net2plan.interfaces.networkDesign.Link;
import com.net2plan.interfaces.networkDesign.Net2PlanException;
import com.net2plan.interfaces.networkDesign.NetPlan;
import com.net2plan.interfaces.networkDesign.NetworkElement;
import com.net2plan.interfaces.networkDesign.NetworkLayer;
import com.net2plan.interfaces.networkDesign.Node;
import com.net2plan.interfaces.networkDesign.ProtectionSegment;
import com.net2plan.interfaces.networkDesign.Route;
import com.net2plan.interfaces.networkDesign.SharedRiskGroup;
import com.net2plan.interfaces.simulation.IEventProcessor;
import com.net2plan.interfaces.simulation.SimEvent;
import com.net2plan.libraries.WDMUtils;
import com.net2plan.utils.Constants.RoutingType;
import com.net2plan.utils.InputParameter;
import com.net2plan.utils.Pair;
import com.net2plan.utils.Quadruple;
import com.net2plan.utils.RandomUtils;
import com.net2plan.utils.Triple;


public class Test_Pro_nfv extends IEventProcessor{
	
	private double stat_trafficOfferedConnections , stat_trafficCarriedConnections;
	private double stat_trafficAttemptedToRecoverConnections , stat_trafficSuccessfullyRecoveredConnections;
	private long stat_numOfferedConnections , stat_numCarriedConnections;
	private long stat_numAttemptedToRecoverConnections , stat_numSuccessfullyRecoveredConnections;
	private double stat_transitoryInitTime;
	
	private int numberofdeployedvnf=0;
	private int mfsi=0;
	private double averagemfsi = 0.0;
	private double averagecost=0.0;
	private int numberofallactivemodulators=0;
	private int numberofactiveBPSK=0;
	private int numberofactiveQPSK=0;
	private int numberofactive8QAM=0;
	private int numberofactive16QAM=0;
	private int numberofactive32QAM=0;
	private int numberofblockedrequests=0;
	private int numberofoccupiedslot=0;
	private int k=0;
	private int numberofhops = 0;
	
	/******************************************************/
	private static int numberofrequests = 100;
	
	private static int numberofallrequests = 2000;
	/******************************************************/
	
	public static int numberofallslot = 358;
	public static int numberofvnftype = 8;
	public static int numberofdcnodes = 14;
	public static int numberofmodulatortype = 5;
	
	List<Integer> numberofVNFlist = new ArrayList<Integer>();
	List<Integer> mfsilist = new ArrayList<Integer>();
	List<Double> avgmfsilist = new ArrayList<Double>();
	List<Integer> numberofhopslist = new ArrayList<Integer>();
	List<Double> averagecostlist = new ArrayList<Double>();
	List<Integer> numberofblockedrequestslist = new ArrayList<Integer>();
	List<Integer> numberofallactivemodulatorslist = new ArrayList<Integer>();
	List<Integer> numberofactiveBPSKlist = new ArrayList<Integer>();
	List<Integer> numberofactiveQPSKlist = new ArrayList<Integer>();
	List<Integer> numberofactive8QAMlist = new ArrayList<Integer>();
	List<Integer> numberofactive16QAMlist = new ArrayList<Integer>();
	List<Integer> numberofactive32QAMlist = new ArrayList<Integer>();
	List<Integer> numberofoccupiedslotlist = new ArrayList<Integer>();
	

	@Override
	public String getDescription() {
		return "Implements the reactions of a VNF service chain request carrying lightpaths in a fixed grid of bandwidth";
	}

	@Override
	public List<Triple<String, String, String>> getParameters() {
		/* Returns the parameter information for all the InputParameter objects defined in this object (uses Java reflection) */
		return InputParameter.getInformationAllInputParameterFieldsOfObject(this);
	}

	@Override
	public void initialize(NetPlan initialNetPlan, Map<String, String> algorithmParameters, Map<String, String> simulationParameters, Map<String, String> net2planParameters) {
		
		/* Initialize all InputParameter objects defined in this object (this uses Java reflection) */
		InputParameter.initializeAllInputParameterFieldsOfObject(this, algorithmParameters);
		
	}

	@Override
	public void processEvent(NetPlan currentNetPlan, SimEvent event) {
		
		k++;
		
		System.out.println("start "+k);
		
		if(k%numberofrequests==1) {
			
			numberofblockedrequests=0;
			numberofhops=0;
			
			String ch = new String() ;
			ch = "D:\\Net2Plan-0.4.0\\workspace\\data\\networkTopologies\\US_Backbone.n2p";
			File f1 = new File(ch);
			NetPlan netplan = new NetPlan(f1);
			
			netplan.setAttribute("OccupiedSlot", "0");
			netplan.setAttribute("MFSI", "0");
			netplan.setAttribute("AvgMFSI", "0");
			netplan.setAttribute("Numberofhops", "0");
			netplan.setAttribute("NumberofdeployedVNF", "0");
			netplan.setAttribute("BlockedRequest", "0");
			netplan.setAttribute("AverageCost", "0");
			netplan.setAttribute("AllActiveModulator", "0");
			netplan.setAttribute("BPSK", "0");
			netplan.setAttribute("QPSK", "0");
			netplan.setAttribute("8QAM", "0");
			netplan.setAttribute("16QAM", "0");
			netplan.setAttribute("32QAM", "0");
			
			/*
			 * ���ѡ���������Ľڵ�
			 * 28���ڵ㣬14���������Ľڵ�
			 * ���ѡ����Ϊ�������Ľڵ�
			 */
			int len = 14; 
	        int[] nums = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27};
	        Set<Integer> set = new HashSet<Integer>();
	        Random random = new Random();
	        int i = 0;
	        while (true) {
	            i = random.nextInt(nums.length);
	            set.add(nums[i]);
	            if(set.size()>=len){
	                break;
	            }
	        }
	       
	        //�õ������нڵ������
	        int numberofnodes = netplan.getNumberOfNodes();
	        
	        for(int j=0;j<numberofnodes;j++) {
	        	
	        	/*
	        	 * �ж�������Ƿ���DC�ڵ�
	        	 * ֮��ͨ�����ԡ�DataCenter�����ж�������Ƿ����������Ľڵ�
	        	 * ��1����ʾ��DC����0����ʾ����DC
	        	 */
	        	
	        	if(set.contains(j)) {
	        		
	        		netplan.getNode(j).setAttribute("DataCenter", "1");
	        		netplan.getNode(j).setAttribute("VNF", "0");
	        		netplan.getNode(j).setAttribute("Reusability", "0");
	        		netplan.getNode(j).setAttribute("ActiveModulator", "0");
	        	}
	        	
	        	else {
	        	
	        		netplan.getNode(j).setAttribute("DataCenter", "0");
	        		netplan.getNode(j).setAttribute("VNF", "0");
	        		netplan.getNode(j).setAttribute("Reusability", "0");
	        		netplan.getNode(j).setAttribute("ActiveModulator", "0");
	        	}
	        	
	        }
	        
	        
	        
	        netplan = Combination10.removeLayers(netplan);
	        netplan = Combination10.removeAllLayerDemand(netplan);
	        netplan = Combination10.substrateNetplanAttribute(netplan);
	        
	        
	        ch = "D:\\Net2Plan-0.4.0\\workspace\\data\\networkTopologies\\US_Backbone.n2p";
			File f_1= new File(ch);
			netplan.saveToFile(f_1);
		}
		
		
		if (event.getEventType()==200) {
			
			NetPlan VNFnetplan = (NetPlan)event.getEventObject();
			
			String ch = new String() ;
			ch = "D:\\Net2Plan-0.4.0\\workspace\\data\\networkTopologies\\US_Backbone.n2p";
			File f1 = new File(ch);
			currentNetPlan = new NetPlan(f1);
			
			numberofhops=numberofhops+VNFnetplan.getNumberOfNodes()-1;
			
			int numberofsublinks = currentNetPlan.getNumberOfLinks(currentNetPlan.getNetworkLayerDefault());
			int numberofsubnodes = currentNetPlan.getNumberOfNodes();
			
			List<Node> subnodelist = currentNetPlan.getNodes();
			List<Integer> dcindexlist = new ArrayList<Integer>();
			
			for(Node node:subnodelist) {
				if(node.getAttribute("DataCenter").equals("1")) {
					dcindexlist.add(subnodelist.indexOf(node));
				}
			}
			
			System.out.println("index of dc node :");
			for(int i:dcindexlist) {
				System.out.print(i+" ");
			}
			
			System.out.println();

			LinkMappingReturn linkmappingreturn = new LinkMappingReturn();
			NodeMappingReturn nodemappingreturn = new NodeMappingReturn();
			
			currentNetPlan = Combination10.removeLayers(currentNetPlan);
			currentNetPlan = Combination10.removeAllLayerDemand(currentNetPlan);
			nodemappingreturn = Combination10.nodeMapping(VNFnetplan,currentNetPlan);
			
			if(nodemappingreturn.isSign()) {
				
				linkmappingreturn = Combination10.linkMapping(VNFnetplan, currentNetPlan);

				if(linkmappingreturn.sign) {
					System.out.println("This request has been successfully serviced!");
				}
				
				else {
					System.out.println("LinkMapping Failed!");
					numberofblockedrequests++;
				}
			}
			else {
				System.out.println("NodeMapping Failed!");
				numberofblockedrequests++;
			}
			
			//������������
			currentNetPlan.setAttribute("BlockedRequest", String.valueOf(numberofblockedrequests));
			System.out.println("Number of blocked requests is: "+numberofblockedrequests);
			
			//VNF����
			numberofdeployedvnf = Combination10.numberofDeployedVNF(currentNetPlan);
			currentNetPlan.setAttribute("NumberofdeployedVNF", String.valueOf(numberofdeployedvnf));
			System.out.println("number of VNF in network is "+numberofdeployedvnf);
			
			//MFSI
			mfsi = Combination10.MFSI(currentNetPlan);
			currentNetPlan.setAttribute("MFSI", String.valueOf(mfsi));
			System.out.println("MFSI in network is "+mfsi);
			
			//ƽ��MFSI
			averagemfsi = Combination10.AvgMFSI(currentNetPlan);
			currentNetPlan.setAttribute("AvgMFSI", String.valueOf(averagemfsi));
			System.out.println("AvgMFSI in network is "+averagemfsi);
			
			//����������
			numberofallactivemodulators=Combination10.AllActiveModulator(currentNetPlan);
			currentNetPlan.setAttribute("AllActiveModulator", String.valueOf(numberofallactivemodulators));
			System.out.println("Number of all active modulators is : "+numberofallactivemodulators);
			
			//���������
			currentNetPlan.setAttribute("Numberofhops", String.valueOf(numberofhops));
			System.out.println("Number of hops in network is "+numberofhops);
			
			//ƽ������
			averagecost = (mfsi*1.0/numberofallslot)+(numberofdeployedvnf*1.0/(numberofvnftype*numberofdcnodes))+(numberofallactivemodulators*1.0/numberofhops);
			currentNetPlan.setAttribute("AverageCost", String.valueOf(averagecost));
			System.out.println("Averagecost of network is "+averagecost);
			
			//BPSK����
			numberofactiveBPSK = Combination10.ActiveBPSK(currentNetPlan);
			currentNetPlan.setAttribute("BPSK", String.valueOf(numberofactiveBPSK));
			System.out.println("Number of active BPSK is : "+numberofactiveBPSK);
			
			//QPSK����
			numberofactiveQPSK = Combination10.ActiveQPSK(currentNetPlan);
			currentNetPlan.setAttribute("QPSK", String.valueOf(numberofactiveQPSK));
			System.out.println("Number of active QPSK is: "+numberofactiveQPSK);
			
			//8QAM����
			numberofactive8QAM = Combination10.Active8QAM(currentNetPlan);
			currentNetPlan.setAttribute("8QAM", String.valueOf(numberofactive8QAM));
			System.out.println("Number of active 8QAM is: "+numberofactive8QAM);
			
			//16QAM����
			numberofactive16QAM = Combination10.Active16QAM(currentNetPlan);
			currentNetPlan.setAttribute("16QAM", String.valueOf(numberofactive16QAM));
			System.out.println("Number of active 16QAM is: "+numberofactive16QAM);
			
			//32QAM����
			numberofactive32QAM = Combination10.Active32QAM(currentNetPlan);
			currentNetPlan.setAttribute("32QAM", String.valueOf(numberofactive32QAM));
			System.out.println("Number of active 32QAM is: "+numberofactive32QAM);
			
			//ռ�õ�slot��
			numberofoccupiedslot = Combination10.busySlot(currentNetPlan);
			currentNetPlan.setAttribute("OccupiedSlot", String.valueOf(numberofoccupiedslot));
			System.out.println("Number of occupied slot is: "+numberofoccupiedslot);
			
			
			
			System.out.println("------------------------------------------------------------------------------");
			
			String sh = new String() ;
			sh = "D:\\Net2Plan-0.4.0\\workspace\\data\\networkTopologies\\US_Backbone.n2p";
			File f_1= new File(sh);
			currentNetPlan.saveToFile(f_1);
		
			
			if(k%numberofrequests==0) {
				numberofVNFlist.add(numberofdeployedvnf);
				mfsilist.add(mfsi);
				avgmfsilist.add(averagemfsi);
				numberofhopslist.add(numberofhops);
				averagecostlist.add(averagecost);
				numberofblockedrequestslist.add(numberofblockedrequests);
				numberofallactivemodulatorslist.add(numberofallactivemodulators);
				numberofactiveBPSKlist.add(numberofactiveBPSK);
				numberofactiveQPSKlist.add(numberofactiveQPSK);
				numberofactive8QAMlist.add(numberofactive8QAM);
				numberofactive16QAMlist.add(numberofactive16QAM);
				numberofactive32QAMlist.add(numberofactive32QAM);
				numberofoccupiedslotlist.add(numberofoccupiedslot);
			}
			
			if(k==numberofallrequests) {
				
				String ah = new String() ;
				ah = "C:\\Users\\PML\\Desktop\\5modes\\mrdp_"+numberofrequests+"requests.txt";
				
				Read.appendMethodB(ah,"�����е�VNF����Ϊ��  " +Combination10.getAvgvalue(numberofVNFlist));
				Read.appendMethodB(ah,"\r\n");
				
				Read.appendMethodB(ah,"�����е�MFSIΪ��  "+Combination10.getAvgvalue(mfsilist));
				Read.appendMethodB(ah,"\r\n");

				Read.appendMethodB(ah,"�����ܵĵ�������Ϊ�� "+Combination10.getAvgvalue(numberofallactivemodulatorslist));
				Read.appendMethodB(ah,"\r\n");
				
				Read.appendMethodB(ah,"����ƽ��������Ϊ�� "+Combination10.getAvgvalue(numberofhopslist));
				Read.appendMethodB(ah,"\r\n");
				
				Read.appendMethodB(ah,"�����ƽ������Ϊ�� "+Combination10.getDoubleAvgvalue(averagecostlist));
				Read.appendMethodB(ah,"\r\n");
				
				Read.appendMethodB(ah,"�����е�ƽ��MFSIΪ��  "+Combination10.getDoubleAvgvalue(avgmfsilist));
				Read.appendMethodB(ah,"\r\n");
				
				Read.appendMethodB(ah,"������ռ�õ�slot��Ϊ�� "+Combination10.getAvgvalue(numberofoccupiedslotlist));
				Read.appendMethodB(ah,"\r\n");
				
				Read.appendMethodB(ah,"������ƽ��ռ�õ�slot��Ϊ�� "+Combination10.getAvgvalue(numberofoccupiedslotlist)/(numberofsublinks*1.0));
				Read.appendMethodB(ah,"\r\n");
				
				Read.appendMethodB(ah,"������������Ϊ�� "+Combination10.getAvgvalue(numberofblockedrequestslist));
				Read.appendMethodB(ah,"\r\n");
				
				Read.appendMethodB(ah,"������BPSK��Ϊ�� "+Combination10.getAvgvalue(numberofactiveBPSKlist));
				Read.appendMethodB(ah,"\r\n");
				
				Read.appendMethodB(ah,"������QPSK��Ϊ�� "+Combination10.getAvgvalue(numberofactiveQPSKlist));
				Read.appendMethodB(ah,"\r\n");
				
				Read.appendMethodB(ah,"������8QAM��Ϊ�� "+Combination10.getAvgvalue(numberofactive8QAMlist));
				Read.appendMethodB(ah,"\r\n");
				
				Read.appendMethodB(ah,"������16QAM��Ϊ�� "+Combination10.getAvgvalue(numberofactive16QAMlist));
				Read.appendMethodB(ah,"\r\n");
				
				Read.appendMethodB(ah,"������32QAM��Ϊ�� "+Combination10.getAvgvalue(numberofactive32QAMlist));
				Read.appendMethodB(ah,"\r\n");
				
				
				Read.appendMethodB(ah,"****************************************************************************************************************************");
				Read.appendMethodB(ah,"\r\n");
			}
			
			
		}
		
		else throw new Net2PlanException ("Unknown event type: " + event);
		
		
	}
	
	
	@Override
	public String finish(StringBuilder output, double simTime)
	{
		final double trafficBlockingOnConnectionSetup = stat_trafficOfferedConnections == 0? 0 : 1 - (stat_trafficCarriedConnections / stat_trafficOfferedConnections );
		final double connectionBlockingOnConnectionSetup = stat_numOfferedConnections == 0? 0.0 : 1 - (((double) stat_numCarriedConnections) / ((double) stat_numOfferedConnections));
		final double successProbabilityRecovery = stat_numAttemptedToRecoverConnections == 0? 0.0 : (((double) stat_numSuccessfullyRecoveredConnections) / ((double) stat_numAttemptedToRecoverConnections));
		final double successProbabilityTrafficRecovery = stat_trafficAttemptedToRecoverConnections == 0? 0.0 : (((double) stat_trafficSuccessfullyRecoveredConnections) / ((double) stat_trafficAttemptedToRecoverConnections));
		final double dataTime = simTime - stat_transitoryInitTime;
		if (dataTime <= 0) { output.append ("<p>No time for data acquisition</p>"); return ""; }

		output.append (String.format("<p>Total traffic of offered connections: number connections %d, total time average traffic: %f</p>", stat_numOfferedConnections, stat_trafficOfferedConnections / dataTime));
		output.append (String.format("<p>Total traffic of carried connections: number connections %d, total time average traffic: %f</p>", stat_numCarriedConnections, stat_trafficCarriedConnections / dataTime));
		output.append (String.format("<p>Blocking at connection setup: Probability of blocking a connection: %f, Fraction of blocked traffic: %f</p>", connectionBlockingOnConnectionSetup , trafficBlockingOnConnectionSetup));
		output.append (String.format("<p>Number connections attempted to recover: %d (summing time average traffic: %f). </p>", stat_numAttemptedToRecoverConnections, stat_trafficAttemptedToRecoverConnections / dataTime));
		output.append (String.format("<p>Number connections successfully recovered: %d (summing time average traffic: %f). </p>", stat_numSuccessfullyRecoveredConnections, stat_trafficSuccessfullyRecoveredConnections / dataTime));
		output.append (String.format("<p>Probability of successfully recover a connection: %f. Proability weighted by the connection traffic: %f). </p>", successProbabilityRecovery, successProbabilityTrafficRecovery));
//		output.append (String.format("<p>Total traffic carried at current state: %f. </p>", -1);
		return "";
	}

	@Override
	public void finishTransitory(double simTime)
	{
		this.stat_trafficOfferedConnections = 0;
		this.stat_trafficCarriedConnections = 0;
		this.stat_trafficAttemptedToRecoverConnections  = 0;
		this.stat_trafficSuccessfullyRecoveredConnections = 0;
		this.stat_numOfferedConnections = 0;
		this.stat_numCarriedConnections = 0;
		this.stat_numAttemptedToRecoverConnections = 0;
		this.stat_numSuccessfullyRecoveredConnections = 0;
		this.stat_transitoryInitTime = simTime;
	}

}
